package com.ruoyi.common.utils.pay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;

import java.io.IOException;
import java.io.StringReader;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.*;

@SuppressWarnings("all")
public class SignUtils {
    private static final Logger log = LoggerFactory.getLogger(SignUtils.class);


    //聚合支付签名算法
    public static  String signJH(Map<String, String> params, String secret){
        String sign="";
        StringBuilder sb = new StringBuilder();
        sb.append("version").append("=").append(params.get("version")).append("&")
                .append("customerid").append("=").append(params.get("customerid")).append("&")
                .append("totalfee").append("=").append(params.get("totalfee")).append("&")
                .append("sdorderno").append("=").append(params.get("sdorderno")).append("&")
                .append("notifyurl").append("=").append(params.get("notifyurl")).append("&")
                .append("returnurl").append("=").append(params.get("returnurl")).append("&");
        sb.append("apikey=").append(secret);
        byte[] md5Digest;
        try {
            //得到Md5加密得到sign
            md5Digest = getMD5Digest(sb.toString());
            sign = byte2hex(md5Digest).toLowerCase();
        } catch (IOException e) {
            System.out.println("生成签名错误" + e);
        }
        return sign;
    }
    //聚合回调签名算法
    public static String signJHNotify(Map<String, String> params, String secret){
        String sign="";
        StringBuilder sb = new StringBuilder();
        sb.append("customerid").append("=").append(params.get("customerid")).append("&")
                .append("totalfee").append("=").append(params.get("totalfee")).append("&")
                .append("sdorderno").append("=").append(params.get("sdorderno")).append("&")
                .append("sdpayno").append("=").append(params.get("sdpayno")).append("&")
                .append("paytype").append("=").append(params.get("paytype")).append("&");
        sb.append("apikey=").append(secret);
        byte[] md5Digest;
        try {
            //得到Md5加密得到sign
            md5Digest = getMD5Digest(sb.toString());
            sign = byte2hex(md5Digest).toLowerCase();
        } catch (IOException e) {
            System.out.println("生成签名错误" + e);
        }
        return sign;
    }

    //签名算法
    public static  String sign(Map<String, String> params, String secret){
        String sign="";
        StringBuilder sb = new StringBuilder();
        //step1：先对请求参数排序
        Set<String> keyset = params.keySet();
        TreeSet<String> sortSet = new TreeSet<String>();
        sortSet.addAll(keyset);
        Iterator<String> it = sortSet.iterator();
        //step2：把参数的key value链接起来 secretkey放在最后面，得到要加密的字符串
        while(it.hasNext())
        {
            String key = it.next();
            String value = params.get(key);
            sb.append(key).append("=").append(value).append("&");
        }
        sb.append("key=").append(secret);
        log.info("签名地址：{}",sb.toString());
        byte[] md5Digest;
        try {
            //得到Md5加密得到sign
            md5Digest = getMD5Digest(sb.toString());
            sign = byte2hex(md5Digest);
        } catch (IOException e) {
            System.out.println("生成签名错误" + e);
        }
        return sign;
    }

    //签名算法
    public static  String signGoods(Map<String, String> params, String secret){
        String sign="";
        StringBuilder sb = new StringBuilder();
        //step1：先对请求参数排序
        Set<String> keyset = params.keySet();
        TreeSet<String> sortSet = new TreeSet<String>();
        sortSet.addAll(keyset);
        Iterator<String> it = sortSet.iterator();
        //step2：把参数的key value链接起来 secretkey放在最后面，得到要加密的字符串
        while(it.hasNext())
        {
            String key = it.next();
            String value = params.get(key);
            sb.append(key).append("=").append(value).append("&");

        }
        sb.append("sign=").append(secret);
        log.info("验证地址：{}",sb.toString());
        byte[] md5Digest;
        try {
            //得到Md5加密得到sign
            md5Digest = getMD5Digest(sb.toString());
            sign = byte2hex(md5Digest);
        } catch (IOException e) {
            System.out.println("生成签名错误" + e);
        }
        return sign;
    }

    private static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }

    private static byte[] getMD5Digest(String data) throws IOException {
        byte[] bytes = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            bytes = md.digest(data.getBytes("UTF-8"));
        } catch (GeneralSecurityException gse) {
            throw new IOException(gse);
        }
        return bytes;
    }
    /**
     * 获取聚合订单查询签名
     * @param params
     * @param secret
     * @return
     */
    public static  String signQueryOrderJH(Map<String, String> params, String secret){
        String sign="";
        StringBuilder sb = new StringBuilder();
        sb.append("version").append("=").append(params.get("version")).append("&")
                .append("customerid").append("=").append(params.get("customerid")).append("&")
                .append("sdorderno").append("=").append(params.get("sdorderno")).append("&")
                .append("apikey=").append(secret);
        byte[] md5Digest;
        try {
            //得到Md5加密得到sign
            md5Digest = getMD5Digest(sb.toString());
            sign = byte2hex(md5Digest).toLowerCase();
        } catch (IOException e) {
            System.out.println("生成签名错误" + e);
        }
        return sign;
    }

    /**
     * 过滤参数
     * @author
     * @param sArray
     * @return
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {
        Map<String, String> result = new HashMap<String, String>(sArray.size());
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }

    /** <�?句话功能�?�?>
     * <功能详细描述>验证返回参数
     * @param params
     * @param key
     * @return
     * @see [类�?�类#方法、类#成员]
     */
    public static boolean checkParam(Map<String,String> params,String key){
        boolean result = false;
        if(params.containsKey("sign")){
            String sign = params.get("sign");
            params.remove("sign");
            StringBuilder buf = new StringBuilder((params.size() +1) * 10);
            SignUtils.buildPayParams(buf,params,false);
            String preStr = buf.toString();
            String signRecieve = MD5.sign(preStr, "&key=" + key, "utf-8");
            result = sign.equalsIgnoreCase(signRecieve);
        }
        return result;
    }

    /**
     * @author
     * @param payParams
     * @return
     */
    public static void buildPayParams(StringBuilder sb,Map<String, String> payParams,boolean encoding){
        List<String> keys = new ArrayList<String>(payParams.keySet());
        Collections.sort(keys);
        for(String key : keys){
            sb.append(key).append("=");
            if(encoding){
                sb.append(urlEncode(payParams.get(key)));
            }else{
                sb.append(payParams.get(key));
            }
            sb.append("&");
        }
        sb.setLength(sb.length() - 1);
    }

    public static String urlEncode(String str){
        try {
            return URLEncoder.encode(str, "UTF-8");
        } catch (Throwable e) {
            return str;
        }
    }

    /**
     * 生成签名字段
     *
     * @param map
     * @return
     */
    public static String buildMapSign(TreeMap<String, String> map, String key) {
        Map<String, String> params = SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() + 1) * 10);
        SignUtils.buildPayParams(buf, params, false);
        String preStr = buf.toString();
        String sign = MD5.sign(preStr, "&key=" + key, "utf-8");
        return sign;
    }

    public static String buildStrSign(String preStr, String key) {
        String sign = MD5.sign(preStr, "&key=" + key, "utf-8");
        return sign;
    }

    public static String getSortJson(JSONObject json) {
        Set<String> iteratorKeys = json.keySet();
        TreeSet<String> sortSet = new TreeSet<String>();
        sortSet.addAll(iteratorKeys);
        Iterator<String> it = sortSet.iterator();
        SortedMap map = new TreeMap();
        while (it.hasNext()) {
            String key = it.next();
            String value = json.getString(key);
            map.put(key, value);
        }

        return JSON.toJSONString(map);
    }

    /**
     * 生成签名字段
     *
     * @param map
     * @return
     */
    public static String buildSign(TreeMap<String, String> map, String key) {
        Map<String, String> params = SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() + 1) * 10);
        SignUtils.buildPayParams(buf, params, false);
        String preStr = buf.toString();
        String sign = MD5.sign(preStr, "&key=" + key, "utf-8");
        return sign;
    }

    /**富信支付验签*/
    public static String signFXNotify(Map<String, String> params, String secret){
        String sign="";
        StringBuilder sb = new StringBuilder();
        sb.append(FXPayConfig.applyId).append(params.get("sdorderno")).append(params.get("goods_id")).append(secret);
        System.out.println(sb.toString());
        byte[] md5Digest;
        try {
            //得到Md5加密得到sign
            md5Digest = getMD5Digest(sb.toString());
            sign = byte2hex(md5Digest).toLowerCase();
        } catch (IOException e) {
            System.out.println("生成签名错误" + e);
        }
        return sign;
    }
    public static String signFXQuery(Map<String, String> params, String secret){
        String sign="";
        StringBuilder sb = new StringBuilder();
        sb.append(params.get("appid")).append(params.get("sdorderno")).append(secret);
        byte[] md5Digest;
        try {
            //得到Md5加密得到sign
            md5Digest = getMD5Digest(sb.toString());
            sign = byte2hex(md5Digest).toLowerCase();
        } catch (IOException e) {
            System.out.println("生成签名错误" + e);
        }
        return sign;
    }


}
